﻿using Apewer.Internals.Interop;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Reflection;
using System.Diagnostics;

#if NETFX || NETCORE
using Microsoft.Win32;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms;
#endif

using static Apewer.Internals.Interop.SHCore;

namespace Apewer.Surface
{

    /// <summary>窗体实用工具。</summary>
    [SecuritySafeCritical]
    public static class FormsUtility
    {

        /// <summary>线程锁。</summary>
        public static object ThreadLocker = new object();

        /// <summary>已使用系统 DPI 设置。</summary>
        public static bool UsedSystemDPI { get; private set; }

        internal static Nullable<float> DpiScale { get; set; }

#if NETFX || NETCORE

        /// <summary>窗体启动初始化。</summary>
        [STAThread]
        public static void StartInitialization(bool useSystemDPI = false)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
#if NETCORE
            Application.SetHighDpiMode(HighDpiMode.SystemAware);
#endif
            // Application.SetCompatibleTextRenderingDefault(true);

            if (useSystemDPI) UseSystemDPI();
        }

        /// <summary>使用系统的 DPI 设置。</summary>
        public static void UseSystemDPI()
        {
            if (UsedSystemDPI) return;
            UsedSystemDPI = true;

#if NETCORE
            Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
#else
            SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_System_DPI_Aware);
            Marshal.GetLastWin32Error();
            PROCESS_DPI_AWARENESS awareness;
            GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
            Marshal.GetLastWin32Error();
#endif
        }

        /// <summary>禁用跨线程调用检查。</summary>
        public static void CrossThread()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

#endif

        #region 线程

        /// <summary>在拥有此控件的基础窗口句柄的线程上执行指定的委托。</summary>
        public static void Invoke(this Control control, Action action)
        {
            if (control == null) throw new ArgumentNullException(nameof(control));
            if (action == null) throw new ArgumentNullException(nameof(action));

            // control.Invoke(action as Delegate);

            control.Invoke(new Action(delegate ()
            {
                action.Invoke();
            }));
        }

        /// <summary>在创建控件的基础句柄所在线程上异步执行指定委托。</summary>
        /// <exception cref="ArgumentNullException" />
        public static IAsyncResult BeginInvoke(this Control control, Action action)
        {
            if (control == null) throw new ArgumentNullException(nameof(control));
            if (action == null) throw new ArgumentNullException(nameof(action));

            // control.BeginInvoke(action as Delegate);

            return control.BeginInvoke(new Action(delegate ()
            {
                action.Invoke();
            }));
        }

        /// <summary>控件属于当前线程。</summary>
        /// <exception cref="ArgumentNullException" />
        public static bool OnCurrentThread(Control control)
        {
            if (control == null) throw new ArgumentNullException(nameof(control));

            var controlThreadId = User32.GetWindowThreadProcessId(new HandleRef(control, control.Handle), out int _);
            var currentThreadId = Kernel32.GetCurrentThreadId();
            return controlThreadId == currentThreadId;
        }

        #endregion

        #region 颜色。

        /// <summary>获取所有可枚举的颜色。</summary>
        public static Color[] EnumerableColor
        {
            get
            {
                var list = new List<Color>();

                list.Add(Color.AliceBlue);
                list.Add(Color.AntiqueWhite);
                list.Add(Color.Aqua);
                list.Add(Color.Aquamarine);
                list.Add(Color.Azure);

                list.Add(Color.Beige);
                list.Add(Color.Bisque);
                list.Add(Color.Black);
                list.Add(Color.BlanchedAlmond);
                list.Add(Color.Blue);
                list.Add(Color.BlueViolet);
                list.Add(Color.Brown);
                list.Add(Color.BurlyWood);

                list.Add(Color.CadetBlue);
                list.Add(Color.Chartreuse);
                list.Add(Color.Chocolate);
                list.Add(Color.Coral);
                list.Add(Color.CornflowerBlue);
                list.Add(Color.Cornsilk);
                list.Add(Color.Crimson);
                list.Add(Color.Cyan);

                list.Add(Color.DarkBlue);
                list.Add(Color.DarkCyan);
                list.Add(Color.DarkGoldenrod);
                list.Add(Color.DarkGray);
                list.Add(Color.DarkGreen);
                list.Add(Color.DarkKhaki);
                list.Add(Color.DarkMagenta);
                list.Add(Color.DarkOliveGreen);
                list.Add(Color.DarkOrange);
                list.Add(Color.DarkOrchid);
                list.Add(Color.DarkRed);
                list.Add(Color.DarkSalmon);
                list.Add(Color.DarkSeaGreen);
                list.Add(Color.DarkSlateBlue);
                list.Add(Color.DarkSlateGray);
                list.Add(Color.DarkTurquoise);
                list.Add(Color.DarkViolet);
                list.Add(Color.DeepPink);
                list.Add(Color.DeepSkyBlue);
                list.Add(Color.DimGray);
                list.Add(Color.DodgerBlue);

                list.Add(Color.Firebrick);
                list.Add(Color.FloralWhite);
                list.Add(Color.ForestGreen);
                list.Add(Color.Fuchsia);

                list.Add(Color.Gainsboro);
                list.Add(Color.GhostWhite);
                list.Add(Color.Gold);
                list.Add(Color.Goldenrod);
                list.Add(Color.Gray);
                list.Add(Color.Green);
                list.Add(Color.GreenYellow);

                list.Add(Color.Honeydew);
                list.Add(Color.HotPink);

                list.Add(Color.IndianRed);
                list.Add(Color.Indigo);
                list.Add(Color.Ivory);

                list.Add(Color.Khaki);

                list.Add(Color.Lavender);
                list.Add(Color.LavenderBlush);
                list.Add(Color.LawnGreen);
                list.Add(Color.LemonChiffon);
                list.Add(Color.LightBlue);
                list.Add(Color.LightCoral);
                list.Add(Color.LightCyan);
                list.Add(Color.LightGoldenrodYellow);
                list.Add(Color.LightGray);
                list.Add(Color.LightGreen);
                list.Add(Color.LightPink);
                list.Add(Color.LightSalmon);
                list.Add(Color.LightSeaGreen);
                list.Add(Color.LightSkyBlue);
                list.Add(Color.LightSlateGray);
                list.Add(Color.LightSteelBlue);
                list.Add(Color.LightYellow);
                list.Add(Color.Lime);
                list.Add(Color.LimeGreen);
                list.Add(Color.Linen);

                list.Add(Color.Magenta);
                list.Add(Color.Maroon);
                list.Add(Color.MediumAquamarine);
                list.Add(Color.MediumBlue);
                list.Add(Color.MediumOrchid);
                list.Add(Color.MediumPurple);
                list.Add(Color.MediumSeaGreen);
                list.Add(Color.MediumSlateBlue);
                list.Add(Color.MediumSpringGreen);
                list.Add(Color.MediumTurquoise);
                list.Add(Color.MediumVioletRed);
                list.Add(Color.MidnightBlue);
                list.Add(Color.MintCream);
                list.Add(Color.MistyRose);
                list.Add(Color.Moccasin);

                list.Add(Color.NavajoWhite);
                list.Add(Color.Navy);

                list.Add(Color.OldLace);
                list.Add(Color.Olive);
                list.Add(Color.OliveDrab);
                list.Add(Color.Orange);
                list.Add(Color.OrangeRed);
                list.Add(Color.Orchid);

                list.Add(Color.PaleGoldenrod);
                list.Add(Color.PaleGreen);
                list.Add(Color.PaleTurquoise);
                list.Add(Color.PaleVioletRed);
                list.Add(Color.PapayaWhip);
                list.Add(Color.PeachPuff);
                list.Add(Color.Peru);
                list.Add(Color.Pink);
                list.Add(Color.Plum);
                list.Add(Color.PowderBlue);
                list.Add(Color.Purple);

                list.Add(Color.Red);
                list.Add(Color.RosyBrown);
                list.Add(Color.RoyalBlue);

                list.Add(Color.SaddleBrown);
                list.Add(Color.Salmon);
                list.Add(Color.SandyBrown);
                list.Add(Color.SeaGreen);
                list.Add(Color.SeaShell);
                list.Add(Color.Sienna);
                list.Add(Color.Silver);
                list.Add(Color.SkyBlue);
                list.Add(Color.SlateBlue);
                list.Add(Color.SlateGray);
                list.Add(Color.Snow);
                list.Add(Color.SpringGreen);
                list.Add(Color.SteelBlue);

                list.Add(Color.Tan);
                list.Add(Color.Teal);
                list.Add(Color.Thistle);
                list.Add(Color.Tomato);
                //list.Add(Color.Transparent);
                list.Add(Color.Turquoise);

                list.Add(Color.Violet);

                list.Add(Color.Wheat);
                list.Add(Color.White);
                list.Add(Color.WhiteSmoke);

                list.Add(Color.Yellow);
                list.Add(Color.YellowGreen);

                return list.ToArray();
            }
        }

        /// <summary>用于填充背景色。</summary>
        public static Color GraceWall { get { return Color.FromArgb(0xff, 0xf7, 0xf7, 0xf7); } }

        /// <summary>用于控件边框。</summary>
        public static Color GraceBorder { get { return Color.FromArgb(0xff, 0xdf, 0xdf, 0xdf); } }

        /// <summary>用于无效的文本、备注文本。</summary>
        public static Color GraceLocked { get { return Color.FromArgb(0xff, 0x7f, 0x7f, 0x7f); } }

        /// <summary>用于次级文本。</summary>
        public static Color GraceMinor { get { return Color.FromArgb(0xff, 0x3f, 0x3f, 0x3f); } }

        /// <summary>用于焦点状态的控件边框。</summary>
        public static Color GraceSilver { get { return Color.FromArgb(0xff, 0xbf, 0xbf, 0xbf); } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Transparent { get { return Color.Transparent; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Black { get { return Color.Black; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color White { get { return Color.White; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Gray { get { return Color.Gray; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color DarkGray { get { return Color.DarkGray; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color LightGray { get { return Color.LightGray; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Red { get { return Color.Red; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Green { get { return Color.Green; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Blue { get { return Color.Blue; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Orange { get { return Color.DarkOrange; } }

        /// <summary>系统定义的颜色。</summary>
        public static Color Purple { get { return Color.Purple; } }

        /// <summary>随机主题色。</summary>
        public static Color RandomColor
        {
            get { var colors = EnumerableColor; return colors[NumberUtility.Random(colors.Length - 1)]; }
        }

        /// <summary>计算 Alpha 合成颜色（基色），基色均需计算。</summary>
        /// <param name="alpha">前景色 Alpha 值。</param>
        /// <param name="back">背景色（基色）。</param>
        /// <param name="fore">前景色（基色）。</param>
        /// <param name="depth">颜色深度，最大值。</param>
        /// <returns>合成后的颜色（基色）。</returns>
        public static int MixAlpha(int alpha, int fore, int back, int depth = 255)
        {
            int b = back, f = fore;
            if (b > depth) b = depth; if (b < 0) b = 0;
            if (f > depth) f = depth; if (f < 0) f = 0;
            int v = fore * alpha / depth + back * (depth - alpha) / depth;
            if (v > depth) v = depth; if (v < 0) v = 0;
            return v;
        }

        /// <summary>按 Alpha 混合不透明的颜色。</summary>
        /// <param name="backColor">背景色。</param>
        /// <param name="foreColor">前景色。</param>
        /// <param name="foreAlpha">前景 Alpha 值。</param>
        /// <returns>混合后的颜色。</returns>
        public static Color MixAlpha(Color backColor, Color foreColor, int foreAlpha)
        {
            var r = MixAlpha(backColor.R, foreColor.R, foreAlpha);
            var g = MixAlpha(backColor.G, foreColor.G, foreAlpha);
            var b = MixAlpha(backColor.B, foreColor.B, foreAlpha);
            var a = MixAlpha(backColor.A, foreColor.A, foreAlpha);
            return Color.FromArgb(a, r, g, b);
        }

        #endregion

        #region 屏幕。

#if NETFX || NETCORE

        /// <summary>获取屏幕的截图。</summary>
        public static Bitmap[] ScreenShot()
        {
            var list = new List<Bitmap>();
            var all = Screen.AllScreens;
            foreach (var screen in all)
            {
                int vw = screen.Bounds.Width;
                int vh = screen.Bounds.Height;
                int vd = screen.BitsPerPixel;
                Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb);
                Graphics g = Graphics.FromImage(b);
                g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh));
                g.Dispose();
                list.Add(b);
            }
            return list.ToArray();
        }

        /// <summary>获取指定屏幕的截图。</summary>
        /// <param name="screen">屏幕号。</param>
        internal static Bitmap ScreenShot(int screen)
        {
            var a = Screen.AllScreens;
            if ((a.Length > 0) && (screen >= 0) && (screen < a.Length))
            {
                try
                {
                    int w = a[screen].Bounds.Width;
                    int h = a[screen].Bounds.Height;
                    int d = a[screen].BitsPerPixel;
                    Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb);
                    Graphics g = Graphics.FromImage(b);
                    g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h));
                    g.Dispose();
                    return b;
                }
                catch { }
            }
            return new Bitmap(0, 0, PixelFormat.Format32bppArgb);
        }

        /// <summary>获取指定屏幕的截图。</summary>
        /// <param name="screen">屏幕，若为 Null 则选择主屏幕。</param>
        internal static Bitmap ScreenShot(Screen screen)
        {
            if (screen == null)
            {
                try
                {
                    int w = Screen.PrimaryScreen.Bounds.Width;
                    int h = Screen.PrimaryScreen.Bounds.Height;
                    int d = Screen.PrimaryScreen.BitsPerPixel;
                    Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb);
                    Graphics g = Graphics.FromImage(b);
                    g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h));
                    g.Dispose();
                    return b;
                }
                catch { }
            }
            return new Bitmap(0, 0, PixelFormat.Format32bppArgb);
        }

#endif

        #endregion

        #region Aero

        /// <summary>获取 DWM 的 Composition 启用状态。</summary>
        public static bool DwmIsCompositionEnabled
        {
            get => DwmApi.DwmIsCompositionEnabled();
        }

        #endregion

        #region 窗体。

#if NETFX || NETCORE

        /// <summary>移动窗体。</summary>
        public static void MoveForm(Form form)
        {
            if (form != null) MoveForm(form.Handle);
        }

        /// <summary>移动窗体。</summary>
        public static void MoveForm(IntPtr form)
        {
            User32.ReleaseCapture();
            User32.SendMessage(form, 0x112, new IntPtr(Constant.SC_MOVE + 2), new IntPtr(0));
        }

        /// <summary>启用鼠标穿透。</summary>
        public static void MousePenetration(Form form)
        {
            if (form != null) MousePenetration(form.Handle);
        }

        /// <summary>启用鼠标穿透。</summary>
        public static void MousePenetration(IntPtr form)
        {
            int intExTemp = User32.GetWindowLong(form, Constant.GWL_EXSTYLE);
            int oldGWLEx = User32.SetWindowLong(form, Constant.GWL_EXSTYLE, Constant.WS_EX_TRANSPARENT | Constant.WS_EX_LAYERED);
        }

        /// <summary>将窗体最大化，不覆盖任务栏。</summary>
        /// <param name="form">窗体。</param>
        public static void ToMaximum(Form form)
        {
            if (form != null)
            {
                var s = Screen.FromControl(form);
                var r = s.WorkingArea;
                if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height))
                {
                    form.MaximumSize = r.Size;
                }
                form.Location = r.Location;
                form.Size = r.Size;
            }
        }

        /// <summary>用指定图像绘制窗体，窗体与图像的大小必须一致。</summary>
        /// <param name="form">要绘制的窗体。</param>
        /// <param name="image">要使用的图像。</param>
        public static void UpdateShadow(Form form, Image image)
        {
            if ((form != null) && (image != null))
            {
                Bitmap vbitmap;
                if ((form.Width != image.Width) || (form.Height != image.Height))
                {
                    vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero));
                }
                else
                {
                    vbitmap = new Bitmap(image);
                }

                var screendc = User32.GetDC(IntPtr.Zero);
                var location = new Internals.Interop.Point(form.Left, form.Top);
                var size = new Internals.Interop.Size(form.Width, form.Height);
                var compatibledc = Gdi32.CreateCompatibleDC(screendc);
                var handle = vbitmap.GetHbitmap(Color.FromArgb(0));
                var oldbitmap = Gdi32.SelectObject(compatibledc, handle);
                var srcloc = new Internals.Interop.Point(0, 0);
                var blendfunction = new BlendFunction();

                blendfunction.blendop = Constant.AC_SRC_OVER;
                blendfunction.sourceconstantalpha = byte.Parse("255");
                blendfunction.alphaformat = Constant.AC_SRC_ALPHA;
                blendfunction.blendflags = 0;
                User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA);

                if (handle != IntPtr.Zero)
                {
                    Gdi32.SelectObject(compatibledc, oldbitmap);
                    Gdi32.DeleteObject(handle);
                }
                User32.ReleaseDC(IntPtr.Zero, screendc);
                Gdi32.DeleteDC(compatibledc);
            }
        }

        /// <summary>为窗体启用阴影。</summary>
        /// <param name="form">要启用阴影的窗体。</param>
        public static void EnableShadow(Form form)
        {
            if (form == null) return;
            int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE);
            User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW);
        }

        /// <summary>恢复任务栏中窗体标题的右键菜单。</summary>
        public static void SetTaskMenu(Form form)
        {
            if (form != null)
            {
                var hwnd = form.Handle;
                var href = new HandleRef(form, hwnd);
                int windowLong = (User32.GetWindowLong(hwnd, -16));
                User32.SetWindowLong(hwnd, -16, windowLong | Constant.WS_SYSMENU | Constant.WS_MINIMIZEBOX);
            }
        }

#endif

        #endregion

        #region 控件。

#if NETFX || NETCORE

        /// <summary>在主界面中移动控件，由目标控件取代当前控件，形成切换控件的动画。</summary>
        /// <param name="current">当前显示的控件。</param>
        /// <param name="target">将要显示的目标控件。</param>
        public static void AnimateGoPanel(Control current, Control target)
        {
            AnimateGoPanel(current.Location, current.Size, 0, 10, current, target, true);
        }

        /// <summary>在主界面中移动控件，由目标控件取代当前控件，形成切换控件的动画。</summary>
        /// <param name="current">当前显示的控件。</param>
        /// <param name="target">将要显示的目标控件。</param>
        /// <param name="next">向左移动。</param>
        public static void AnimateGoPanel(Control current, Control target, bool next)
        {
            AnimateGoPanel(current.Location, current.Size, 0, 10, current, target, next);
        }

        /// <summary>在主界面中移动控件，由目标控件取代当前控件，形成切换控件的动画。</summary>
        /// <param name="point">控件左上角坐标。</param>
        /// <param name="size">控件大小。</param>
        /// <param name="span">当前控件和目标控件的间距，若值小于 0 则更正为 0 。</param>
        /// <param name="frame">移动的次数，若值小于 0 则更正为 20。</param>
        /// <param name="current">当前显示的控件。</param>
        /// <param name="target">将要显示的目标控件。</param>
        /// <param name="next">向左移动。</param>
        public static void AnimateGoPanel(System.Drawing.Point point, System.Drawing.Size size, int span, int frame, Control current, Control target, bool next = true)
        {
            int s = (span < 0) ? span : 0;
            int step = (current.Width + s) / ((frame < 1) ? 20 : frame);
            int x = point.X;
            int y = point.Y;
            current.Size = size;
            target.Size = size;
            current.Location = point;
            if (next)
            {
                target.Location = new System.Drawing.Point(size.Width, point.Y);
                current.Visible = true;
                target.Visible = true;
                Application.DoEvents();
                while (target.Left > x)
                {
                    s = ((target.Left - x) < step) ? (target.Left - x) : step;
                    target.Left -= s;
                    current.Left -= s;
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(1);
                }
            }
            else
            {
                target.Location = new System.Drawing.Point(x - size.Width, x);
                current.Visible = true;
                target.Visible = true;
                Application.DoEvents();
                while (target.Left < x)
                {
                    s = ((x - target.Left) < step) ? x - target.Left : step;
                    target.Left += s;
                    current.Left += s;
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(1);
                }
            }
            current.Visible = false;
        }

        /// <summary>设置窗体置顶。</summary>
        public static void SetTopMost(IntPtr form, bool value = true)
        {
            if (form == null || form == IntPtr.Zero) return;
            User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3);
        }

        /// <summary>设置窗体置顶。</summary>
        public static void SetTopMost(Form form, bool value = true)
        {
            if (form != null) SetTopMost(form.Handle, value);
        }

        /// <summary>释放系统资源。</summary>
        public static void Dispose(Control control)
        {
            if (control == null) return;

            if (control.InvokeRequired)
            {
                control.Invoke(() => Dispose(control));
                return;
            }

            Dispose(control.Controls);

            if (control is Form form)
            {
                try
                {
                    if (form.Visible) form.Close();
                }
                catch { }
            }

            RuntimeUtility.Dispose(control);
        }

        /// <summary>释放系统资源。</summary>
        public static void Dispose(Control.ControlCollection controls)
        {
            if (controls == null) return;

            var count = controls.Count;
            if (count < 1) return;

            var children = new Control[count];
            controls.CopyTo(children, 0);

            foreach (var child in children)
            {
                controls.Remove(child);
                Dispose(child);
            }
        }

#endif

        #endregion

        #region 绘图。

#if NETFX || NETCORE

        /// <summary>绘制内边框。</summary>
        /// <param name="image">源图像。</param>
        /// <param name="border">边框颜色。</param>
        public static bool PaintBorder(ref Image image, Color border)
        {
            if (image != null)
            {
                var g = Graphics.FromImage(image);
                var p = new Pen(border);

                g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
                p.Dispose();
                g.Dispose();
                return true;
            }
            else return false;
        }

        /// <summary>绘制内边框。</summary>
        /// <param name="image">源图像。</param>
        /// <param name="border">边框颜色。</param>
        public static bool PaintBorder(ref Bitmap image, Color border)
        {
            if (image != null)
            {
                var g = Graphics.FromImage(image);
                var p = new Pen(border);

                g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
                p.Dispose();
                g.Dispose();
                return true;
            }
            else return false;
        }

        /// <summary>绘制内边框。</summary>
        /// <param name="image">源图像。</param>
        /// <param name="border">边框颜色。</param>
        /// <param name="wall">背景颜色。</param>
        public static bool PaintBorder(ref Image image, Color border, Color wall)
        {
            if (image != null)
            {
                var g = Graphics.FromImage(image);
                var p = new Pen(border);

                g.Clear(wall);

                g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
                p.Dispose();
                g.Dispose();
                return true;
            }
            else return false;
        }

        /// <summary>建立带有圆角样式的路径。</summary>
        /// <param name="rect">建立矩形路径的区域。</param>
        /// <param name="radius">圆角的大小。</param>
        /// <returns>建立的路径。</returns>
        public static GraphicsPath CreatePath(Rectangle rect, int radius = 0)
        {
            GraphicsPath path = new GraphicsPath();
            int r = (radius < 0) ? 0 : radius;
            switch (r)
            {
                case 0:
                    path.AddRectangle(rect);
                    break;
                default:
                    path.AddArc(rect.X, rect.Y, r, r, 180, 90);
                    path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90);
                    path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90);
                    path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90);
                    break;
            }
            path.CloseFigure();
            return path;
        }

        /// <summary></summary>
        /// <param name="location"></param>
        /// <param name="size"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        public static GraphicsPath GetRadiusPath(PointF location, SizeF size, float radius)
        {
            var loc = location;
            var rds = Math.Abs(radius);
            var path = new GraphicsPath();

            float x, y, r;
            r = rds * 2;

            // 左上角。
            x = loc.X;
            y = loc.Y;
            path.AddArc(x, y, r, r, 180, 90);

            // 右上角。
            x = loc.X + size.Width - rds * 2;
            y = loc.Y;
            path.AddArc(x, y, r, r, 270, 90);

            // 左下角。
            x = loc.X;
            y = loc.Y + size.Height - rds * 2;
            path.AddArc(x, y, r, r, 0, 90);

            // 右下角。
            x = loc.X + size.Width - rds * 2;
            y = loc.Y + size.Height - rds * 2;
            path.AddArc(x, y, r, r, 90, 90);

            // 边框直线：上、下、左、右。
            path.AddLine((float)(loc.X + rds), (float)loc.Y, (float)(loc.X + size.Width - rds), (float)loc.Y);
            path.AddLine((float)(loc.X + rds), (float)(loc.Y + size.Height), (float)(loc.X + size.Width - rds), (float)(loc.Y + size.Height));
            path.AddLine((float)loc.X, (float)(loc.Y + rds), (float)loc.X, (float)(loc.Y + size.Height - rds));
            path.AddLine((float)(loc.X + size.Width), (float)(loc.Y + rds), (float)(loc.X + size.Width), (float)(loc.Y + size.Height - rds));

            return path;
        }

        /// <summary>获取指定文件中的图标总数。</summary>
        public static int GetIconsCount(string path)
        {
            if (!File.Exists(path)) return 0;
            var count = User32.PrivateExtractIcons(path, 0, 0, 0, null, null, 0, 0);
            return count;
        }

        /// <summary>获取指定文件中的图标。</summary>
        public static Bitmap[] GetIconsBitmap(string path = null, int size = 256)
        {
            if (string.IsNullOrEmpty(path)) path = Application.ExecutablePath;

            if (!File.Exists(path)) return null;
            var count = User32.PrivateExtractIcons(path, 0, 0, 0, null, null, 0, 0);

            var ptrs = new IntPtr[count];
            var ids = new int[count];
            var succeed = User32.PrivateExtractIcons(path, 0, size, size, ptrs, ids, count, 0);

            var images = new Bitmap[count];
            for (var i = 0; i < succeed; i++)
            {
                if (ptrs[i] == IntPtr.Zero) continue;
                using (var icon = Icon.FromHandle(ptrs[i]))
                {
                    var bitmap = icon.ToBitmap();
                    images[i] = bitmap;
                }
                User32.DestroyIcon(ptrs[i]);
            }

            return images;
        }

        /// <summary>从文件获取图标。</summary>
        public static Icon GetExecutableIcon(string path)
        {
            try { return Icon.ExtractAssociatedIcon(path); }
            catch { return null; }
        }

#endif

        #endregion

        #region 字体。

        private const string FontYahei = "Microsoft Yahei";
        private const string FontSimsun = "Simsun";
        private const string GuiFontRegKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\GRE_Initialize";

        private static string _fontname = "";

        /// <summary>存在微软雅黑字体。</summary>
        public static bool MsyhExist { get => File.Exists("c:\\windows\\fonts\\msyh.ttc"); }

        /// <summary>获取默认字体名称。</summary>
        public static string DefaultFontName
        {
            get
            {
                if (!string.IsNullOrEmpty(_fontname)) return _fontname;
                try
                {
                    if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei;
                    else return FontSimsun;
                }
                catch { return FontSimsun; }
            }
        }

        /// <summary>获取默认字体名称。</summary>
        public static string GuiFontName { get => Registry.GetValue(GuiFontRegKey, "GUIFont.Facename", "Arial") as string; }

        /// <summary>获取默认字体大小。</summary>
        public static float GuiFontSize { get => Convert.ToSingle(Registry.GetValue(GuiFontRegKey, "GUIFont.Height", 9F)); }

#if NETFX || NETCORE

        /// <summary>获取默认字体。</summary>
        public static Font GuiFont { get => new Font(GuiFontName, GuiFontSize); }

        /// <summary>获取默认字体。</summary>
        public static Font DefaultFont
        {
            get { return new Font(DefaultFontName, 9); }
        }

        /// <summary>获取大小为 9 的默认字体。</summary>
        public static Font NewFont()
        {
            return new Font(DefaultFontName, 9);
        }

        /// <summary>获取指定大小的默认字体。</summary>
        public static Font NewFont(float size)
        {
            return new Font(DefaultFontName, size);
        }

        /// <summary>获取指定大小的默认字体。</summary>
        public static Font NewFont(float size, bool bold)
        {
            return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular);
        }

        /// <summary>从文件加载字体，并获取指定字体。</summary>
        /// <param name="path">文件路径。</param>
        /// <param name="index">文件中的 Font Family 索引，默认取第一个（索引 0）。</param>
        /// <returns>已存在的 Font Family，如果指定的索引处不存在 Font Family，则返回 NULL 值。</returns>
        public static FontFamily LoadFont(string path, int index = 0)
        {
            if (index < 0) return null;
            if (string.IsNullOrEmpty(path)) return null;
            if (!File.Exists(path)) return null;

            try
            {
                var pfc = new PrivateFontCollection();
                pfc.AddFontFile(path);
                var fs = pfc.Families;
                if (fs.Length > 0 && index < fs.Length) return fs[index];
            }
            catch { }
            return null;
        }

#if NET40 || NET461

        /// <summary></summary>
        public static List<System.Windows.Media.FontFamily> ListFileFont(string path)
        {
            try
            {
                var collection = System.Windows.Media.Fonts.GetFontFamilies(path);
                var list = new List<System.Windows.Media.FontFamily>(collection.Count);
                foreach (var item in collection) list.Add(item);
                return list;
            }
            catch { }
            return new List<System.Windows.Media.FontFamily>();
        }

        /// <summary></summary>
        public static List<System.Windows.Media.FontFamily> ListSystemFont()
        {
            var collection = System.Windows.Media.Fonts.SystemFontFamilies;
            var list = new List<System.Windows.Media.FontFamily>(collection.Count);
            foreach (var item in collection) list.Add(item);
            return list;
        }

        /// <summary>枚举指定字体中的所有字符。</summary>
        public static List<char> EnumerateFontChars(IEnumerable<System.Windows.Media.Typeface> typefaces)
        {
            var chars = new List<char>();
            if (typefaces != null)
            {
                foreach (var typeface in typefaces)
                {
                    var subs = EnumerateFontChars(typeface);
                    if (subs != null) chars.AddRange(subs);
                }
            }
            return chars;
        }

        /// <summary>枚举指定字体中的所有字符。</summary>
        public static char[] EnumerateFontChars(System.Windows.Media.Typeface typeface)
        {
            System.Windows.Media.GlyphTypeface glyph;
            var tried = typeface.TryGetGlyphTypeface(out glyph);
            if (glyph == null) return null;

            var map = glyph.CharacterToGlyphMap;
            var keys = map.Keys;
            var chars = new List<char>(keys.Count);
            for (int i = 0; i < keys.Count; i++)
            {
                var index = System.Linq.Enumerable.ElementAt(keys, i);
                try
                {
                    var c = Convert.ToChar(index);
                    chars.Add(c);
                }
                catch { }
            }
            return chars.ToArray();
        }

#endif

        /// <summary>获取已安装的字体。</summary>
        public static List<FontFamily> ListInstalledFonts()
        {
            var list = new List<FontFamily>();
            int ret = 0; // Win32 API 返回值，非零值均为异常。

            // 初始化 FontCollection。
            var collection = new Internals.FontCollection();
            ret = GdiPlus.GdipNewInstalledFontCollection(out collection.NativePointer);
            if (ret != 0) return list;

            // 获取字体总数。
            int found1 = 0;
            ret = GdiPlus.GdipGetFontCollectionFamilyCount(new HandleRef(collection, collection.NativePointer), out found1);
            if (ret != 0) return list;

            // 获取字体指针。
            var ptrs = new IntPtr[found1];
            int found2 = 0;
            ret = GdiPlus.GdipGetFontCollectionFamilyList(new HandleRef(collection, collection.NativePointer), found1, ptrs, out found2);
            if (ret != 0) return list;

            // 获取字体列表。
            list.Capacity = found2;
            for (int i = 0; i < found2; i++)
            {
                IntPtr cloned;
                GdiPlus.GdipCloneFontFamily(new HandleRef(null, ptrs[i]), out cloned);
                try
                {
                    var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance;
                    var args = new object[] { cloned };
                    var instance = Activator.CreateInstance(typeof(FontFamily), flags, null, args, null, null);
                    var item = instance as FontFamily;
                    if (item != null) list.Add(item);
                }
                catch { }
            }

            list.Capacity = list.Count;
            return list;
        }

        private static bool GlyphExists(char c, Font font)
        {
            using (var dummy = Graphics.FromImage(new Bitmap(1, 1)))
            {
                IntPtr hdc = dummy.GetHdc();
                var pgi = new ushort[1];
                try
                {
                    IntPtr hfont = font.ToHfont();
                    Gdi32.SelectObject(hdc, hfont);
                    string str = c.ToString();
                    Gdi32.GetGlyphIndices(hdc, str, str.Length, pgi, Constant.GGI_MARK_NONEXISTING_GLYPHS);
                }
                catch { }
                dummy.ReleaseHdc(hdc);

                // 0xFFFF 表示字形不存在。
                return (pgi[0] != 0xffff);
            }
        }

#endif

        #endregion

        #region WndProc

        /// <summary>允许鼠标调整窗体大小。此方法对 FormBorderStyle 为 None 的窗体生效。</summary>
        /// <returns>已处理事件。</returns>
        /// <exception cref="ArgumentNullException" />
        /// <exception cref="ArgumentOutOfRangeException" />
        public static bool AllowResizeForm(this Form form, ref Message m, int padding = 4)
        {
            if (form == null) throw new ArgumentNullException(nameof(form));
            if (form.FormBorderStyle != FormBorderStyle.None) return false;

            if (padding < 0) throw new ArgumentOutOfRangeException(nameof(padding));

            const int HT_LEFT = 10;
            const int HT_RIGHT = 11;
            const int HT_TOP = 12;
            const int HT_TOP_LEFT = 13;
            const int HT_TOP_RIGHT = 14;
            const int HT_BOTTOM = 15;
            const int HT_BOTTOM_LEFT = 16;
            const int HT_BOTTOM_RIGHT = 17;

            switch (m.Msg)
            {
                case 0x0084:
                    var clientSize = form.ClientSize;
                    var screenPoint = new System.Drawing.Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF);
                    var point = form.PointToClient(screenPoint);
                    if (point.X <= padding)
                    {
                        if (point.Y <= padding) m.Result = (IntPtr)HT_TOP_LEFT;
                        else if (point.Y >= clientSize.Height - padding) m.Result = (IntPtr)HT_BOTTOM_LEFT;
                        else m.Result = (IntPtr)HT_LEFT;
                        return true;
                    }
                    else if (point.X >= clientSize.Width - padding)
                    {
                        if (point.Y <= padding) m.Result = (IntPtr)HT_TOP_RIGHT;
                        else if (point.Y >= clientSize.Height - padding) m.Result = (IntPtr)HT_BOTTOM_RIGHT;
                        else m.Result = (IntPtr)HT_RIGHT;
                        return true;
                    }
                    else if (point.Y <= padding)
                    {
                        m.Result = (IntPtr)HT_TOP;
                        return true;
                    }
                    else if (point.Y >= clientSize.Height - padding)
                    {
                        m.Result = (IntPtr)HT_BOTTOM;
                        return true;
                    }
                    break;
            }

            return false;
        }

        /// <summary>允许移动窗体。左键点击时修改消息，认为鼠标点在非客户区（标题栏）。</summary>
        /// <returns>已处理事件。</returns>
        /// <exception cref="ArgumentNullException" />
        public static bool AllowMoveForm(this Form form, ref Message m)
        {
            if (form == null) throw new ArgumentNullException(nameof(form));

            switch (m.Msg)
            {
                // 左键点击时修改消息，认为鼠标点在非客户区（标题栏）。
                case 0x0201:
                    m.Msg = 0x00A1;
                    m.LParam = IntPtr.Zero;
                    m.WParam = new IntPtr(2);
                    return true;
            }

            return false;
        }

        #endregion

    }

}
